Analyzing a Project Areas Members and Roles Using The Plain Java Client Libraries


I was interested in how to read the data from a Project and Team Area. This post shows my progress so far.

The purpose of the endeavor really is to be able to create a new project area from a certain template project area, copying over all information. I am not even nearly there yet. However Jian’s question on Jazz.net indicates that what I found so far might be interesting anyhow. If you are just starting with extending Rational Team Concert, start reading this and the linked posts to get some guidance on how to set up your environment.

License and how to get started with the RTC API’S

As always, our lawyers reminded me to state that the code in this post is derived from examples from Jazz.net as well as the RTC SDK. The usage of code from that example source code is governed by this license. Therefore this code is governed by this license, which basically means you can use it for internal usage, but not sell. Please also remember, as stated in the disclaimer, that this code comes with the usual lack of promise or guarantee. Enjoy!

If you just get started with extending Rational Team Concert, or create API based automation, start with the post Learning To Fly: Getting Started with the RTC Java API’s and follow the linked resources.

You should be able to use the following code in this environment and get your own automation or extension working.

To keep it simple this example is, as many others in this blog, based on the Jazz Team Wiki entry on Programmatic Work Item Creation and the Plain Java Client Library Snippets. The example in this blog shows RTC Client API.

Download

You can download the code from here.

* Update *

The code to launch the methods is included in the download. It can also be found in several of the older posts, for example in Uploading Attachments to Work Items in the main() and the run() methods.

As a general statement, you should use the Java API to access the process information and not try to read the XML of the process directly. Please be aware that only the API documented in the Plain Java Client Library JavaDoc documentation is public API. You might end up using internal API and that is subject to change. Even for the public API there is no guarantee that it won’t change as far as I know.

You can access similar information by using the Generate Runtime Report on the project area’s context menu as shown below.

Generate Runtime Report*Update*

This code also works for

Finding a Project Area

The code provided either iterates over all project areas of a repository, or it finds the project area with a given name. Once it has located the project area, it calls the method analyzeProjectArea(teamRepository, projectArea) that takes care for the details.

The code needs some data. You can call it by providing the RepositoryURI, the user and password and optional a project area name like in the examples below.

Here the interesting code in the main method.

if (projectAreaName == null) {
	// For all project areas
	IProcessItemService itemService = (IProcessItemService) teamRepository
		.getClientLibrary(IProcessItemService.class);
	List pAreas = itemService.findAllProjectAreas(null, null);
	for (Iterator iterator = pAreas.iterator(); iterator.hasNext();) {
		IProjectArea projectArea = (IProjectArea) iterator.next();
		analyzeProjectArea(teamRepository, projectArea);
	}
} else {
	// For a specific project area
	IProcessClientService processClient = (IProcessClientService) teamRepository
		.getClientLibrary(IProcessClientService.class);

	URI uri = URI.create(projectAreaName.replaceAll(" ", "%20"));
	IProjectArea projectArea = (IProjectArea) processClient.findProcessArea(uri, null, null);
	if (projectArea == null) {
		System.out.println("Project area not found.");
		return false;
	}
	analyzeProjectArea(teamRepository, projectArea);
}

Analyzing The Project Area

The code below is called and prints the process area description and the contributors for the project area and then iterates the team area hierarchy doing the same.

/**
 * Analyze a project area
 *
 * @param teamRepository
 * @param projectArea
 * @throws TeamRepositoryException
 */
public static void analyzeProjectArea(ITeamRepository teamRepository,
		IProjectArea projectArea) throws TeamRepositoryException {
	printProcessAreaDescription(teamRepository, projectArea);
	dumpContributors(teamRepository, projectArea);
	List teamAreas = projectArea.getTeamAreas();
	for (Iterator iterator = teamAreas.iterator(); iterator.hasNext();) {
		ITeamAreaHandle handle = (ITeamAreaHandle) iterator.next();
		ITeamArea teamArea = (ITeamArea) teamRepository.itemManager()
			.fetchCompleteItem(handle, IItemManager.DEFAULT, null);

		printProcessAreaDescription(teamRepository, teamArea);
		dumpContributors(teamRepository, teamArea);
	}
}

Printing the Process Area Description

This method prints the process are description that is not accessible as a string but as content attached to the process area.

/**
 * Print the description of the process area
 *
 * @param teamRepository
 * @param pa
 * @throws TeamRepositoryException
 */
public static void printProcessAreaDescription(ITeamRepository teamRepository, IProcessArea pa)
		throws TeamRepositoryException {
	IDescription desc = pa.getDescription();
	IContent content = desc.getDetails();
	String description = "";
	if (content != null) {
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		teamRepository.contentManager().retrieveContent(content, stream, null);
		try {
			description = stream.toString(content.getCharacterEncoding());
		} catch (UnsupportedEncodingException exception) {
			description = stream.toString();
		}
	}
	String summary = desc.getSummary();
	System.out.println(summary + "\n\nDescription:\n" + description);
}

Printing the Administrators and Team Members of a Process Area

This operation prints the contributors associated to the process area. It separates the administrators and the team members.

/**
 * Iterate over the contributors of the process area and print them sorted
 * as admins and as team members
 *
 * @param teamRepository
 * @param processArea
 * @throws TeamRepositoryException
 */
private static void dumpContributors(ITeamRepository teamRepository,
		IProcessArea processArea) throws TeamRepositoryException {
	System.out.println("Process Area: " + processArea.getName());
	System.out.println("Administrators");
	dumpContributors(teamRepository, processArea, processArea.getAdministrators());
	System.out.println("Team Members");
	dumpContributors(teamRepository, processArea, processArea.getMembers());
}

It uses the following code to iterate a list of contributors and print the information.

/**
 * @param teamRepository
 * @param processArea
 * @param contributors
 * @throws TeamRepositoryException
 */
private static void dumpContributors(ITeamRepository teamRepository,
		IProcessArea processArea, IContributorHandle[] contributors)
		throws TeamRepositoryException {

	for (int i = 0; i < contributors.length; i++) {
		IContributorHandle handle = (IContributorHandle) contributors[i];
		dumpContributor(teamRepository, processArea, handle);
	}
}

This code finally does the printing of the details of the contributor.

/**
* Dump the details of the contributors
*
* @param teamRepository
* @param processArea
* @param handle
* @throws TeamRepositoryException
*/
private static void dumpContributor(ITeamRepository teamRepository,
		IProcessArea processArea, IContributorHandle handle)
		throws TeamRepositoryException {
	IContributor contributor = (IContributor) teamRepository.itemManager()
		.fetchCompleteItem(handle, IItemManager.DEFAULT, null);
	System.out.print(": " + contributor.getUserId() + "\t"
		+ contributor.getName() + "\t" + contributor.getEmailAddress()
		+ "\t");
	IProcessItemService processService = (IProcessItemService) teamRepository
		.getClientLibrary(IProcessItemService.class);
	IClientProcess process = processService.getClientProcess(processArea, null);
	IRole[] contributorRoles = process.getContributorRoles(contributor, processArea, null);
	for (int j = 0; j < contributorRoles.length; j++) {
		IRole role = (IRole) contributorRoles[j];
		System.out.print(role.getId() + " ");
	}
	System.out.println();
}

* Update *

I just realized that using IRole there is no way to access the role name. Sometimes along the way the interface probably needed to be made richer and to not break the older version, an additional interface IRole2 was introduced. This code provides with the additional information.

	for (int j = 0; j < contributorRoles.length; j++) {
		IRole role = (IRole) contributorRoles[j];
		IRole2 role2 = (IRole2) role;	
		System.out.print(role.getId() + "[" + role2.getRoleName() +" " + role2.getRoleLabel() + "] ");
	}

Get The Latest Data

The API caches Data. If you want to make sure that the data is refreshed, use IItemManager.REFRESH instead of IItemManager.DEFAULT in the code above.

Only Analyze the Process Areas of One User

This code, result of this question on jazz.net, shows how to get only the process areas a certain user is member of in a repository:

	IContributor user = teamRepository.loggedInContributor();
	// If having an ID for the user as string
	//IContributor user = teamRepository.contributorManager().fetchContributorByUserId(user)
	IProcessItemService processItemService = (IProcessItemService) teamRepository
			.getClientLibrary(IProcessItemService.class);

	List processAreasOfUser= processItemService.findProcessAreas(user, null, IProcessClientService.ALL_PROPERTIES , monitor);

Summary

Using the API as described above allows you to run automation against project areas. although this describes client API, the server API is similar enough and allows you to do similar things for example to extend this example to iterate the team hierarchy.

I hope that these code examples will help users out there that have a need for more automation.

21 thoughts on “Analyzing a Project Areas Members and Roles Using The Plain Java Client Libraries

  1. IProcessItemService itemService = (IProcessItemService) teamRepository
    .getClientLibrary(IProcessItemService.class);
    In the statement above: “teamRepository” gives an error: ‘teamRepository’ cannot be resolved. How is this object initialized?
    I am thinking it should be something along the lines of ITeamRepository teamRepository = “….”

    Please help. Thanks in advance.

    • The whole code is available from a link in the post. Please look into that.

      The basic code is also, as mentioned available in:

      “To keep it simple this example is again based on the wiki entry on Programmatic Work Item Creation. The API used in the following example is client API.” the link is in the post.

      • Hi,

        I downloaded the code and I am trying to run it; where in the code do I type in the parameters (repository address, username, password, and project name)? I am trying to run it, but all it outputs is :
        Usage: PlainJavaClient
        Usage: PlainJavaClient

        Please let me know. thanks!

  2. Hi Ralph,
    regarding analyzing a project area I’d like to also get the information about whether a shared process is used and if so which one. So far, I’m not able to find the correct API calls for querying that. Could you point me in the right direction?

    Thanks for this and your very helpful articles in general!
    Manuel

  3. Hello Ralph,

    This is a nice post to start!

    We have a scenario where we have multiple roles in our process, as far as we know when a user has more than one role then there is a conflict between “required attribute for type and state” and “read only attribute for type an state”.

    Now we have decided to prioritise the roles based on state transition which i think is quite possible, but there seems to be a blocker. When an existing workitem is loaded then is there any triggering point in RTC so that it would re-prioritize the roles of the authenticated user based on the state the workitem is.

    Thanks in Advance.
    Abhishek Kumar

    • This comes to my attention over and over. The only valid answer I know so far is that you should create your own advisor that implements the method for required and read only attributes. You can look into the code in the SDK and create your own logic around it.

  4. Hello Ralph,

    How to get all project areas using server api’s.

    and We have a scenario where we have to create a workitem form one project area that automatically create workitem in another project area, how to do this using server api’s, please help me with this.

    Thanks in advance.
    Manju

    • You can use IProcessService pService = getService(IProcessService.class);
      pService.findProcessAreas(user, projectAreaHandle, properties);

      I have not found a call to get all project areas in the server API yet.

  5. Hi Ralph,
    Does this code print user’s role assignment per project/team or it concatenates all roles within the project’s hierarchy and prints them repeatedly for a member? For example, if a member is assigned the scrum master role at the project level and a team member role at the team level, would it show scrum master + team member for both project and team OR will it show scrum master for the project and team member for the team?

    • Hi,

      this is example code made so that users that need such kind of stuff can grab it and do whatever they want to do with it.

      If I follow the code correctly it will,
      1. show the admins and members for the project area.
      Show the users in the project area with all their roles at that level
      For all team areas
      Show the users in the team area with all their roles at that level

      I would suggest testing what it does and if that is what you want. The code should be downloadable.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.